﻿/**	\file		lolix_inst.h
 *	\date		(2007-03-06 21:21:37)/(2014-11-24 14:58:19)
 *-----------------------------------------------------------------------------
 *	\version	1.0.28.46
 *	\author		Nick Shallery	(nicknide@gmail.com)
 *	\copyright	YOU HAVE ALL LEFT WITH THIS CODE WHILE YOU KEEP COMMENT IN EVERY COPY.
 *-----------------------------------------------------------------------------
**/

#if			!defined(__LOLIX__LOLIX_INSTANCE__K_IN_G__)
#define		__LOLIX__LOLIX_INSTANCE__K_IN_G__
//==============================================================================
//--------------------------------------------------------------------------

#if			!defined(__LOLIX__LOLI_X_CFG__K_IN_G__)
	#include	"./lolix_cfg.h"
#endif	//	!defined(__LOLIX__LOLI_X_CFG__K_IN_G__)

#if			!defined(__LOLIX__LOLI_X_MACRO__K_IN_G__)
	#include	"./lolix_macro.h"
#endif	//	!defined(__LOLIX__LOLI_X_MACRO__K_IN_G__)
#if			!defined(__LOLIX__LOLIX_TYPE__K_IN_G__)
	#include	"./lolix_type.h"
#endif	//	!defined(__LOLIX__LOLIX_TYPE__K_IN_G__)

#if			!defined(__LOLIX__TOY__INVOKE_CAST__HPP__K_IN_G__)
	#include	"./toy/invoke_cast.hpp"
#endif	//	!defined(__LOLIX__TOY__INVOKE_CAST__HPP__K_IN_G__)

namespace lolix{
	class	lolix_inst;
	class	dynamic_allocator;

	namespace sv2
	{
#pragma	pack(push, 8)
		struct	lolix_lib_header
		{
			const LOLIX_ITF_ID*	lid;
			size_type		sver	:  8;
			size_type		cfg_type:  2;
		};

		struct	lolix_init_param
		{
			enum { _ver = 2, def_type = LOLIX_CFG__CFG_TYPE };
			const LOLIX_ITF_ID*	lid;
			size_type		sver	:  8;
			size_type		cfg_type:  2;
			size_type		fill_z	: 22;

			dynamic_allocator*	alc;
			diary*				diary;
		};

		struct	lolix_plugin_param
		{
			enum { _ver = 2, def_type = LOLIX_CFG__CFG_TYPE };
			const LOLIX_ITF_ID*	lid;
			size_type	sver	:  8;
			size_type	cfg_type:  2;
			size_type	u8fs	: 10;
			size_type	fill_z	: 12;

			const lx_pchar*	path;
		};
#pragma	pack(pop)

		template<typename _TyChar>
		LOLIX_INLINE_CALL void __make_id_name_unsafe(_TyChar* buf, const LOLIX_ITF_ID* itf_id)
		{
			lx_u32 const* iid = (lx_u32 const*)itf_id;
			size_type buf_pos = ((size_type)0) - 1;
			for ( size_type i = 0; i != 4; ++i )
			{
				const char* transform_table = "0123456789abcdef";
				lx_u32 val = iid[i];
				for ( size_type k = 0; k != 8; ++k )
				{
					lx_u32 flag = (val>>28);
					buf[++buf_pos] = transform_table[flag & 0x0f];
					val <<= 4;
				}

				if ( i != 3 )
					buf[++buf_pos] = '-';
			}
		}

		LOLIX_INLINE_CALL void __make_lib_fill_subfix(lx_char* buf)
		{
			*((lx_u32*)buf) = *(lx_u32*)".dll";
		}
		LOLIX_INLINE_CALL void __make_lib_fill_subfix(lx_wchar* buf)
		{
			*((lx_u64*)buf) = *(lx_u64*)L".dll";
		}
		template<typename _TyChar, typename _TyBits>
		LOLIX_INLINE_CALL void __make_lib_name_unsafe(_TyChar* buf, const LOLIX_ITF_ID* itf_id, const _TyBits* bits_string, size_type cfg_type)
		{	//	XXXXXXXX-YYYYYYYY-ZZZZZZZZ-WWWWWWWW-x32r.dll
			//	0123456789abcdef0123456789abcdef0123456789abc
			//	0				1				2
			__make_id_name_unsafe(buf, itf_id);
			size_type buf_pos = 0x22;
			buf[++buf_pos] = '-';
			buf[++buf_pos] = 'x';
			buf[++buf_pos] = bits_string[0];
			buf[++buf_pos] = bits_string[1];
			buf[++buf_pos] = "dpr"[cfg_type];
			__make_lib_fill_subfix(buf + (++buf_pos));
			//*((lx_u64*)(buf+ (++buf_pos))) = *(lx_u64*)L".dll";
		}
	}

	namespace sv3
	{
		struct	lolix_init_param
		{
			enum { _ver = 3, def_type = LOLIX_CFG__CFG_TYPE };
			const LOLIX_ITF_ID*	lid;
			size_type		sver		:  8;
			size_type		cfg_type	:  2;
			size_type		auto_iload	: 1;
			size_type		fill_z		: 21;

			dynamic_allocator*	alc;
			diary*				diary;
		};
	}

	typedef sv3::lolix_init_param	lolix_init_param;
	typedef sv2::lolix_plugin_param	lolix_plugin_param;

	template<typename _TyChar, size_type _Vsize>
	LOLIX_INLINE_CALL LOLIX_RETNV make_id_name(_TyChar (&buf)[_Vsize], size_type* start_pos, const LOLIX_ITF_ID* itf_id)
	{
		//										0				1				2
		//										0123456789abcdef0123456789abcdef0123
		const size_type min_buf_size = sizeof( "XXXXXXXX-YYYYYYYY-ZZZZZZZZ-WWWWWWWW");
		size_type out_size;
		if ( !start_pos )
			*(start_pos = &out_size) = 0;
		if ( _Vsize - *start_pos < min_buf_size )
			return LOLIX_ERROR_LESS_MEMORY;
		buf[*start_pos + min_buf_size-1] = 0;
		sv2::__make_id_name_unsafe(buf + *start_pos, itf_id);
		return LOLIX_RETNV_OK;
	}

	template<typename _TyChar, size_type _Vsize, typename _Tbits>
	LOLIX_INLINE_CALL LOLIX_RETNV make_lib_name(_TyChar (&buf)[_Vsize], size_type* start_pos, const LOLIX_ITF_ID* itf_id, const _Tbits (&bits_string)[2], size_type cfg_type)
	{	//	XXXXXXXX-YYYYYYYY-ZZZZZZZZ-WWWWWWWW_x32r.Wll
		const size_type min_buf_size = sizeof("XXXXXXXX-YYYYYYYY-ZZZZZZZZ-WWWWWWWW-x32r.dll");
		size_type out_size;
		if ( !start_pos )
			*(start_pos = &out_size) = 0;

		if ( _Vsize - *start_pos < min_buf_size )
			return LOLIX_ERROR_LESS_MEMORY;
		buf[*start_pos + min_buf_size-1] = 0;
		//lx_wchar bits[2] = {bits_string[0], bits_string[1]};

		sv2::__make_lib_name_unsafe(buf + *start_pos, itf_id, bits_string, cfg_type);
		*start_pos += min_buf_size - 1;
		return LOLIX_RETNV_OK;
	}

	LOLIX_INLINE_CALL LOLIX_RETNV get_lib_cfg_by_name(LOLIX_ITF_ID* itf_id, size_type* bits, size_type* cfg_type, lx_wchar const* name, size_type name_len)
	{
		lx_u32* iid = (lx_u32*)itf_id;
		const size_type min_buf_size = sizeof("XXXXXXXX-YYYYYYYY-ZZZZZZZZ-WWWWWWWW-x32r.dll");
		if ( name_len < min_buf_size - 4 )
			return LOLIX_ERROR_INVALID_PARAM;

		for ( size_type i = 0; i != 4; ++i )
		{
			iid[i] = 0;
			for ( size_type k = 0; k != 8; ++k, ++name )
			{
				iid[i] <<= 4;
				if ( '0' <= *name && *name <= '9' )
					iid[i] += *name - '0';
				else if ( 'a' <= *name && *name <= 'f' )
					iid[i] += *name - 'a' + 10;
				else if ( 'A' <= *name && *name <= 'F' )
					iid[i] += *name - 'A' + 10;
				else
					return LOLIX_ERROR_INVALID_PARAM;
			}
			if ( *name != '-' )
				return LOLIX_ERROR_INVALID_PARAM;
			++name;
		}

		if ( *name != 'x' && *name != 'X' )
			return LOLIX_ERROR_INVALID_PARAM;
		++name;
		if ( *name == '6' )
		{
			if ( name[1] != '4' )
				return LOLIX_ERROR_INVALID_PARAM;
			*bits = 64;
		}
		else if ( *name == '3' )
		{
			if ( name[1] != '2' )
				return LOLIX_ERROR_INVALID_PARAM;
			*bits = 32;
		}
		else
			return LOLIX_ERROR_INVALID_PARAM;
		name += 2;

		switch ( *name )
		{
		case 'd': case 'D':
			*cfg_type = 0;
			break;
		case 'p': case 'P':
			*cfg_type = 1;
			break;
		case 'r': case 'R':
			*cfg_type = 2;
			break;
		default:
			return LOLIX_ERROR_INVALID_PARAM;
		}

		return LOLIX_RETNV_OK;
	}
}


namespace lolix{
	class LOLIX_NO_VTABLE lolix_regist
		: public lolix::itf
	{
	public:
		LOLIX_DECLARE_ITF(lolix::lolix_regist, lolix::itf, (0x52a8843f, 0xa5dc43d4, 0xb58d50e7, 0x01ee12ad));
		//===========================================================================
		//	注册一个对象
		//---------------------------------------------------------------------------
		//	id		[i ] :	注册对象的 ID
		//	i		[i ] :	注册对象的指针
		//---------------------------------------------------------------------------
		//	同一个 id 之能被注册一次
		//===========================================================================
		LOLIX_INTERFACE(reg_loli, lolix::LOLIX_RETNV	, (lolix::LOLIX_ITF_ID const* id, lolix::itf* i));

		//===========================================================================
		//	取消注册一个对象
		//---------------------------------------------------------------------------
		//	id		[i ] :	需要取消注册的对象
		//===========================================================================
		LOLIX_INTERFACE(clr_loli, lolix::LOLIX_RETNV	, (lolix::LOLIX_ITF_ID const* id));

		//===========================================================================
		//	取消所有注册
		//---------------------------------------------------------------------------
		//===========================================================================
		LOLIX_INTERFACE(clear, void	, (void));



		template<typename _Ty>
		LOLIX_INLINE_CALL	LOLIX_RETNV	reg_loli(_Ty* t)
			{
			LOLIX_ITF_ID id;
			LOLIX_ITF_ID_FROM(&id, _Ty);
			return this->reg_loli(&id, t);
			}

		template<typename _Ty>
		LOLIX_INLINE_CALL	LOLIX_RETNV clr_loli(const _Ty* t)
			{
			LOLIX_ITF_ID id;
			LOLIX_ITF_ID_FROM(&id, _Ty);
			return this->clr_loli(&id);
			}
	};

	class LOLIX_NO_VTABLE lolix_factory
		: public lolix::itf
	{
	public:
		LOLIX_DECLARE_ITF(lolix::lolix_factory, lolix::itf, (0xeaf67068, 0x85c07d40, 0x85057b9a, 0xac6783c1));
		LOLIX_INTERFACE(create_inst, LOLIX_RETNV, (itf** out_ptr, LOLIX_ITF_ID const* in_id, lolix_inst* invoked_inst));
		LOLIX_INTERFACE(get_itfs,	size_type	, (LOLIX_ITF_ID const** out_itfs)const);
	};

	class LOLIX_NO_VTABLE lolix_inst
		: public lolix::itf
	{
	public:
		LOLIX_DECLARE_ITF(lolix::lolix_inst, lolix::itf, (0x13f04bfe, 0x8b5f42aa, 0xbae9de08, 0x9005491e));

		class LOLIX_NO_VTABLE plugin_module
			: public lolix::itf
		{
		public:
			LOLIX_DECLARE_ITF(lolix::lolix_inst::plugin_module, lolix::itf, (0x5c25345b, 0x6b5b4ace, 0x9085320d, 0xa7639fa2));
			typedef lolix::toy::invoker_process<bool, false, lolix::toy::type_list<lolix::LOLIX_ITF_ID const*> > _TFN_enum_itfs_callback;
			LOLIX_INTERFACE(unload		, LOLIX_RETNV	, (void));
			LOLIX_INTERFACE(enum_itfs	, void			, (_TFN_enum_itfs_callback callback)const);
			LOLIX_INTERFACE(mod_id		, void			, (lolix::LOLIX_ITF_ID* itf_id)const);
		};

		LOLIX_INTERFACE(get_ver	, size_type		, (void)const);
		LOLIX_INTERFACE(get_cfg	, size_type		, (lolix_cfg* const lx_cfg, size_type lx_cfg_size)const);
		LOLIX_INTERFACE(reg_loli, LOLIX_RETNV	, (LOLIX_ITF_ID const* in_id, itf* i));
		LOLIX_INTERFACE(clr_loli, LOLIX_RETNV	, (LOLIX_ITF_ID const* in_id, itf* i));

		LOLIX_INTERFACE(load	, LOLIX_RETNV	, (plugin_module** mod, lolix_plugin_param const* const plugin_param));

		template<typename _T_LOLI>
		LOLIX_INLINE_CALL	LOLIX_RETNV	reg_loli(_T_LOLI* ll)
			{
			const LOLIX_ITF_ID itf_id(LOLIX_ITF_FROM_TYPE(_T_LOLI));
			return reg_loli(&itf_id, ll);
			}
	};
}

namespace lolix{

	/**
	 * \typedef	LOLIX_RETNV (LOLIX_CALL* fnLxLoadInst)(lolix_inst** out_ptr, const lolix_init_param* in_param)
	 *
	 * \brief	lolix 主模块被加载之后，调用此函数初始化.
	 * \param [out]	out_ptr		得到lolix_inst的入口对象.
	 * \param [in]	in_param	进行初始化的设置.
	 * \return	返回是否插件加载成功
	**/
	typedef LOLIX_RETNV	(LOLIX_CALL* fnLxLoadInst)(lolix_inst** out_ptr, const lolix_init_param* in_param);

	/**
	* \typedef	lolix_init_param const* (LOLIX_CALL* fnLxLibInfo)(void)
	*
	* \brief	得到lolix的初始化所用的信息。
	**/
	typedef lolix_init_param const*	(LOLIX_CALL* fnLxLibInfo)(void);

	/**
	 * \typedef	LOLIX_RETNV (LOLIX_CALL* fnLxFreeLib)(void)
	 *
	 * \brief	lolix 主模块使用完毕之后必须由此释放.
	 * \return	是否释放成功
	**/
	typedef LOLIX_RETNV	(LOLIX_CALL* fnLxFreeLib)(void);

	/**
	 * \typedef	lolix_plugin_param const* (LOLIX_CALL* fnLxpLibInfo)(void)
	 *
	 * \brief	得到插件的基本信息.
	**/
	typedef lolix_plugin_param const*	(LOLIX_CALL* fnLxpLibInfo)(void);

	/**
	 * \typedef	LOLIX_RETNV (LOLIX_CALL* fnLxpLoading)(lolix_inst* lx_inst, lolix_regist* lx_reg)
	 *
	 * \brief	加载插件.
	 * \param [in] lx_inst	已经加载的所有模块信息.
	 * \param [in] lx_reg	需要将接口等注册到此模块中.
	 * \return	返回是否加载成功.
	**/
	typedef LOLIX_RETNV	(LOLIX_CALL* fnLxpLoading)(lolix_inst* lx_inst, lolix_regist* lx_reg);

	/**
	 * \typedef	LOLIX_RETNV (LOLIX_CALL* fnLxpFreeing)(lolix_inst* lx_inst)
	 *
	 * \brief	释放插件模块.
	 * \param	lx_inst	当前的全局对象，供其使用.
	 * \return	LOLIX_IS_ERROR(rtv) 为true表示当前正在使用，不能释放此插件；
	 * 			否则表示可以立即释放此插件.
	**/
	typedef LOLIX_RETNV	(LOLIX_CALL* fnLxpFreeing)(lolix_inst* lx_inst);
}

//--------------------------------------------------------------------------
//==============================================================================
#endif	//	!defined(__LOLIX__LOLIX_INSTANCE__K_IN_G__)
